package com.example.demo.domain.application;

import com.example.demo.domain.application.factory.ApplicationAbstractFactory;
import com.example.demo.domain.category.Category;
import com.example.demo.domain.user.User;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.stereotype.Component;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 企业应用
 *
 * @author yingjianhua
 */
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(callSuper = true)
@Entity
@DiscriminatorValue("COMPANY")
public class CompanyApplication extends Application {

    private CompanyApplication(String name, String icon) {
        super(name, icon);
    }

    @Override
    public boolean isOpen(User user) {
        // 有三种情况说明是开通了的
        // 1. 自己是管理员
        // 2. 相同公司内有一个公司范围的开通记录
        // 3. 个人有开通记录
        return user.getIsManager()
                || openRepository.findByApplicationAndCompanyIdAndScope(this, user.getCompanyId(), OpenRecord.Scope.Company).isPresent()
                || super.isOpen(user);
    }

    /**
     * 进行公司范围的开通
     *
     * @param operator 操作人员
     */
    public void openCompanyScope(User operator) throws Exception {
        openConstrain();
        if (!operator.getIsManager()) {
            throw new Exception("只有管理员能操作");
        }
        // 先删除之前的个人范围的开通记录
        openRepository.findAllByApplicationAndCompanyId(this, operator.getCompanyId()).forEach(openRepository::delete);
        // 新增公司范围的开通记录
        openRepository.save(OpenRecord.createCompanyScope(this, operator.getCompanyId()));
    }

    /**
     * 批量开放权限，不包含在里面的都删除
     *
     * @param userList 用户列表
     */
    public void batchOpen(User operator, List<User> userList) throws Exception {
        openConstrain();
        if (!operator.getIsManager()) {
            throw new Exception("只有管理员能操作");
        }
        // 搜索管理员所在公司的公司范围的开通记录
        final Optional<OpenRecord> openRecordOptional = openRepository.findByApplicationAndCompanyIdAndScope(this, operator.getCompanyId(), OpenRecord.Scope.Company);
        if (openRecordOptional.isPresent()) {
            // 假如存在公司范围的开通记录， 删除之
            openRepository.delete(openRecordOptional.get());
            // 并添加管理员的开通记录
            openRepository.save(OpenRecord.createPersonScope(this, operator));
        }
        final List<OpenRecord> oldList = openRepository.findAllByApplicationAndCompanyId(this, operator.getCompanyId());
        final List<User> noChangeUserList = new ArrayList<>();
        for (OpenRecord old : oldList) {
            if (!userList.contains(old.getUser())) {
                // 如果当前开通用列表中不存在， 需要删除开通记录
                permissionConstrain(operator, old.getUser());
                if (old.getUser().getIsManager()) {
                    // 管理员的开通是不会删除的
                    continue;
                }
                openRepository.delete(old);
            } else {
                noChangeUserList.add(old.getUser());
            }
        }
        for (User user : userList) {
            if (!noChangeUserList.contains(user)) {
                // 如果当前开通记录里面不包含该用户的开通记录，需要进行开通
                permissionConstrain(operator, user);
                openRepository.save(OpenRecord.createPersonScope(this, user));
            }
        }
    }

    @Override
    protected boolean havePermission(User operator, User user) {
        return operator.getIsManager() && operator.sameCompany(user);
    }

    @Component
    public static class CompanyApplicationFactory implements ApplicationAbstractFactory {

        @Override
        public Application create(String name, Category category, String icon) {
            CompanyApplication companyApplication = new CompanyApplication(name, icon);
            repository.save(companyApplication);
            sortService.moveToCategory(companyApplication, category);
            return companyApplication;
        }
    }
}
